const xlsx = require('node-xlsx');
const fs = require('fs');
const path = require('path');
var _ = require('lodash');
const config = require('../config.json');
const types = require('./types');
const parser = require('./parser');

const DataType = types.DataType;
const SheetType = types.SheetType;

// class StringBuffer {
//   constructor(str) {
//     this._str_ = [];
//     if (str) {
//       this.append(str);
//     }
//   }

//   toString() {
//     return this._str_.join("");
//   }

//   append(str) {
//     this._str_.push(str);
//   }
// }


function serializeWorkbookToJsonObj(parsedWorkbook, dest, settings) {
    let result = ""
    for (let name in parsedWorkbook) {
        let sheet = parsedWorkbook[name];
        let resultJson = JSON.stringify(sheet, null, config.json.uglify ? 0 : 2); //, null, 2
        result += `"${name}":${resultJson},`
    }
    return result;
}

/**
 * save workbook
 */
function serializeWorkbookToJson(parsedWorkbook, dest, settings) {

    if (!fs.existsSync(dest)) {
        fs.mkdirSync(dest);
    }
    for (let name in parsedWorkbook) {
        let sheet = parsedWorkbook[name];

        let dest_file = path.resolve(dest, name + ".json");
        let resultJson = JSON.stringify(sheet, null, config.json.uglify ? 0 : 2); //, null, 2

        fs.writeFile(dest_file, resultJson, err => {
            if (err) {
                console.error("error：", err);
                throw err;
            }
            console.log('exported json  -->  ', path.basename(dest_file));
        });
    }
}

/**
 * save workbook
 */
function serializeWorkbookToLua(parsedWorkbook, dest, settings) {
    if (!fs.existsSync(dest)) {
        fs.mkdirSync(dest);
    }
    for (let name in parsedWorkbook) {
        let sheet = parsedWorkbook[name];

        let dest_file = path.resolve(dest, name + ".lua");

        let luaStr = `${name}={` //objToLua(sheet);
        if (!config.lua.uglify) {
            luaStr += "\r\n"
        }

        for (const key in sheet) {
            if (!config.lua.uglify) {
                luaStr += "\t"
            }
            if (sheet instanceof Array) {
            } else if (sheet instanceof Object) {
                luaStr += `["${key}"]=`
            }
            const obj = sheet[key];
            luaStr += objToLua(obj);
            luaStr += ",";
            if (!config.lua.uglify) {
                luaStr += "\r\n"
            }
        }

        luaStr = luaStr.substr(0, luaStr.length - 3);
        if (!config.lua.uglify) {
            luaStr += "\r\n"
        }
        luaStr += "}"
        fs.writeFile(dest_file, luaStr, err => {
            if (err) {
                console.error("error：", err);
                throw err;
            }
            console.log('exported lua  -->  ', path.basename(dest_file));
        });

    }

}

/**
 * js对象转换成lua table 字符串
 * @param {Object} obj ：传入js的对象；
 */
function objToLua(obj) {
    let lua = "";
    if (obj instanceof Array) {
        lua = "{";
        for (let i = 0; i < obj.length; i++) {
            const value = obj[i];
            lua += objToLua(value);
            lua += ","
        }
        lua = lua.substr(0, lua.length - 1);
        lua += "}"
    } else if (typeof (obj) == 'string') {
        lua += `"${obj}"`
    } else if (obj instanceof Object) {
        lua = "{";
        for (const key in obj) {
            lua += `["${key}"]=`
            const value = obj[key];
            lua += objToLua(value);
            lua += ","
        }
        lua = lua.substr(0, lua.length - 1);
        lua += "}"
    }
    else {
        lua += `${obj}`;
    }
    // }
    return lua
};
/**
 * save dts
 */
function serializeWorkbookToTypeScriptEntity(parsedWorkbook, dest, settings) {

    if (!fs.existsSync(dest)) {
        fs.mkdirSync(dest);
    }


    let dts = "";

    for (let name in settings) {
        let setting = settings[name]
        if (setting.type == SheetType.SLAVE) {
            continue;
        }
        dts = formatDTS(name, setting);
        let dest_file = path.resolve(dest, name + ".ts");
        fs.writeFile(dest_file, dts, err => {
            if (err) {
                console.error("error：", err);
                throw err;
            }
            console.log('exported ts  -->  ', path.basename(dest_file));
        });
    }


}


/**
 * 
 * @param {String} name the excel file name will be use on create d.ts
 * @param {Object} head the excel head will be the javescript field
 */
function formatDTS(name, setting) {
    let strHead = "";
    for (let i = 0; i < setting.slaves.length; i++) {
        const slave = setting.slaves[i];
        strHead += formatSlaves(name, slave);
    }
    strHead += `export default interface ${name} {\r\n`;
    for (let i = 0; i < setting.head.length; ++i) {
        let head = setting.head[i];
        let desc = setting.desc[i];

        if (head.name.startsWith('!') || head.name.startsWith('！') || head.name.startsWith('！') || head.name.startsWith('！')) {
            continue;
        }

        let is_slave = _.find(setting.slaves, slave => {
            return slave.name === head.name;
        });

        if (is_slave) {
            continue;
        }

        let typesDes = getTypeDes(head.type);
        strHead += `\t/**${desc}*/\r\n`;
        strHead += `\t${head.name}: ${typesDes};\r\n`;
    }

    for (let i = 0; i < setting.slaves.length; i++) {
        const slave = setting.slaves[i];
        let interfaceName = `${name}_${slave.name}`
        strHead += `\t/**${slave.desc}*/\r\n`;
        strHead += `\t${slave.name}: ${(slave.type === DataType.ARRAY_STR ? `${interfaceName}[]` : interfaceName)};\r\n`;
    }

    strHead += "}\r\n";
    return strHead;
}

/**生成从表 */
function formatSlaves(name, slave) {
    let str = `/**${slave.desc}*/\r\n`
    str += `export interface ${name}_${slave.name} {\r\n`;
    for (let i = 0; i < slave.data.name.length; ++i) {
        let name = slave.data.name[i];
        let desc = slave.data.desc[i];
        let type = slave.data.type[i];

        if (name.startsWith('!') || name.startsWith('！') || name.startsWith('！') || name.startsWith('！')) {
            continue;
        }

        let typesDes = getTypeDes(type);

        str += `\t/**${desc}*/\r\n`;
        str += `\t${name}: ${typesDes};\r\n`;
    }
    str += "}\r\n";
    return str
}

function getTypeDes(type) {
    let typesDes = null;
    if (type === DataType.NUMBER || type === DataType.INT || type === DataType.DOUBLE || type === DataType.FLOAT) {
        typesDes = "number";
    } else if (type === DataType.STRING || type === DataType.ID || type == DataType.IDS) {
        typesDes = "string";
    } else if (type === DataType.BOOL || type === DataType.BOOLEAN) {
        typesDes = "boolean";
    } else if (type === DataType.ARRAY || type === DataType.ARRAY_STR) {
        typesDes = "any[]";
    } else if (type === DataType.ARRAY_STRING) {
        typesDes = "string[]";
    } else if (type === DataType.ARRAY_NUMBER) {
        typesDes = "number[]";
    } else if (type === DataType.ARRAY_BOOL || type === DataType.ARRAY_BOOLEAN) {
        typesDes = "boolean[]";
    } else if (type === DataType.OBJECT || type === DataType.OBJECT_STR) {
        typesDes = "any";
    } else if (type === DataType.UNKNOWN) {
        typesDes = "any";
    } else {
        typesDes = type || "any";
    }
    return typesDes
}

module.exports = {

    /**
     * convert xlsx file to json and save it to file system.
     * @param  {String} src path of .xlsx files.
     * @param  {String} dest       directory for exported json files.
     * @param  {Number} headIndex      index of head line.
     * @param  {String} separator      array separator.
     *
     * excel structure
     * workbook > worksheet > table(row column)
     */
    toJson: function (src, dest, dest_ts, dest_lua) {

        let parsed_src = path.parse(src);

        let workbook = xlsx.parse(src);

        console.log("parsing excel:", parsed_src.base);

        let settings = parser.parseSettings(workbook);

        // let parsed_workbook = parseWorkbook(workbook, dest, headIndex, path.join(dest, parsed_src.name));
        let parsed_workbook = parser.parseWorkbook(workbook, settings);

        if (config.json.export) {
            serializeWorkbookToJson(parsed_workbook, dest, settings);
        }

        if (config.ts) {
            serializeWorkbookToTypeScriptEntity(parsed_workbook, dest_ts, settings);
        }

        if (config.lua.export) {
            serializeWorkbookToLua(parsed_workbook, dest_lua, settings);
        }
    },

    /**合并json */
    mergeJson: function (files, __dirname, dest, dest_ts, dest_lua) {
        let jsonObj = `{`
        files.forEach(item => {
           
            if (item.lastIndexOf(".xlsx") === -1) {
                return;
            }
            if (item[0] == "~") {
                return;
            }
            let src = path.join(__dirname, item);

            let parsed_src = path.parse(src);

            let workbook = xlsx.parse(src);

            console.log("parsing excel:", parsed_src.base);

            let settings = parser.parseSettings(workbook);

            // let parsed_workbook = parseWorkbook(workbook, dest, headIndex, path.join(dest, parsed_src.name));
            let parsed_workbook = parser.parseWorkbook(workbook, settings);

            if (config.json.export) {
                jsonObj += serializeWorkbookToJsonObj(parsed_workbook, dest, settings);
            }
            if (config.ts) {
                serializeWorkbookToTypeScriptEntity(parsed_workbook, dest_ts, settings);
            }

            if (config.lua.export) {
                serializeWorkbookToLua(parsed_workbook, dest_lua, settings);
            }
        });
        jsonObj = jsonObj.substr(0, jsonObj.length - 1);
        jsonObj += "}"
        if (!fs.existsSync(dest)) {
            fs.mkdirSync(dest);
        }

        let dest_file = path.resolve(dest, "config.json");
        fs.writeFile(dest_file, jsonObj, err => {
            if (err) {
                console.error("error：", err);
                throw err;
            }
            console.log('exported json  -->  ', path.basename(dest_file));
        });
    }
};

